/**
 * 该模块提供了 Unicode 字符类别。
 * License: BSD
 * Authors: Lucifer (786325481@QQ.com)
 * Copyright: Copyright (C) 2008 Lucifer. All rights reserved.
 */

module system.globalization.CharUnicodeInfo;

import system.WChar;
import system.globalization.UnicodeCategory;

/**
 * 检索 Unicode 字符的信息。无法继承此类。
 * Comments:
 *		Unicode 标准为 Unicode 字符定义了几种属性，其中之一就是字符的类别。
 *		例如，某个字符可能被归类为大写字母、小写字母、十进制数字、字母数字、连接标点、数学符号或货币符号。
 *		应用程序可以通过字符的类别来控制基于字符串的操作，例如内容分析。
 *
 *		UnicodeCategory 枚举指定字符的 Unicode 类别。
 *		使用 CharUnicodeInfo 类可以获取特定字符的 UnicodeCategory 值。
 *
 *		CharUnicodeInfo 类返回以下 Unicode 字符属性：
 *		数值是一个仅应用于数值型字符的 Unicode 字符属性，数值型字符包括分数、下标、上标、罗马数字、货币分子、循环数和语言特有的数字。
 *		数字值是一个仅应用于可以用作数字的数值型字符的属性。数字是一种数值型字符，它可以与其他数字结合以表示编号系统中的一个整数。
 *		十进制数字值是一个仅应用于十进制数字的属性。十进制数字是十进制（以 10 为基数）系统中的一个数字，它可以是从零到九这十个数字中的一个。
 */
public final class CharUnicodeInfo
{
	private this(){}

	/**
	 * 获取指定数值型字符的十进制数字值。
	 * Params:
	 *		c = 获取其十进制数字值的 Unicode 字符。
	 * Returns:
	 *		指定数值型字符的十进制数字值。
	 *		如果指定字符不是十进制数字则返回 -1 。
	 * Comments:
	 *		十进制数字值是一个仅应用于十进制数字的属性。
	 *		十进制数字是十进制（以 10 为基数）系统中的一个数字，它可以是从零到九这十个数字中的一个。
	 */
	public static int getDecimalDigitValue(wchar c)
	{
		auto i = cast(int)c;
		switch(i)
		{
			// They are not decimal digits but are regarded as they were.
			case 178:
				return 2;
			case 179:
				return 3;
			case 185:
				return 1;
			case 8304:
				return 0;
		}

		// They are not decimal digits but are regarded as they were.
		if (8308 <= i && i < 8314)
			return i - 8304;
		if (8320 <= i && i < 8330)
			return i - 8320;

		if (!WChar.isDigit (c))
			return -1;

		if (i < 58)
			return i - 48;

		if (i < 1642)
			return i - 1632;
		if (i < 1786)
			return i - 1776;
		if (i < 2416)
			return i - 2406;
		if (i < 2544)
			return i - 2534;
		if (i < 2672)
			return i - 2662;
		if (i < 2800)
			return i - 2790;
		if (i < 2928)
			return i - 2918;
		if (i < 3056)
			return i - 3046;
		if (i < 3184)
			return i - 3174;
		if (i < 3312)
			return i - 3302;
		if (i < 3440)
			return i - 3430;
		if (i < 3674)
			return i - 3664;
		if (i < 3802)
			return i - 3792;
		if (i < 3882)
			return i - 3872;
		if (i < 4170)
			return i - 4160;
		if (i < 4978)
			return i - 4968;
		if (i < 6122)
			return i - 6112;
		if (i < 6170)
			return i - 6160;
		if (i < 8314)
			return i - 8304;
		if (i < 8330)
			return i - 8320;
		if (i < 65296)
			return -1;
		if (i < 65306)
			return i - 65296;
		return -1;
	}

	/**
	 * 获取位于指定字符串的指定索引位置的数值型字符的十进制数字值。
	 * Params:
	 *		str = 要查询的字符串。
	 *		index = str 中的字符位置。
	 * Returns:
	 *		位于指定字符串的指定索引位置的数值型字符的十进制数字值。
	 *		如果指定字符串的指定索引位置的数值型字符不是十进制数字则返回 -1 。
	 * Throws:
	 *		AsserError，当 str 为 null 或者 index 超出了 str 中的有效索引范围。
	 * Comments:
	 *		ditto 。
	 */
	public static int getDecimalDigitValue(wstring str, int index)
	in
	{
		checkParameter(str, index);
	}
	body
	{
		return getDecimalDigitValue(str[index]);
	}

	/**
	 * 获取指定数值型字符的数字值。
	 * Params:
	 *		c = 要获取其数字值的 Unicode 字符。
	 * Returns:
	 *		指定数值型字符的数字值。
	 *		如果指定字符不是数字则返回 -1 。
	 * Comments:
	 *		数字值是一个仅应用于可以用作数字的数值型字符的属性。
	 *		数字是一种数值型字符，它可以与其他数字结合以表示编号系统中的一个整数。
	 */
	public static int getDigitValue(wchar c)
	{
		auto i = getDecimalDigitValue (c);

		if (i >= 0)
			return i;
		i = cast(int)c;

		if (i == 9450)
			return 0;

		// They are False in WChar.isDigit(), but returns a digit
		if (i >= 9312 && i < 9321)
			return i - 9311;
		if (i >= 9332 && i < 9341)
			return i - 9331;
		if (i >= 9352 && i < 9361)
			return i - 9351;
		if (i >= 9461 && i < 9470)
			return i - 9460;
		if (i >= 10102 && i < 10111)
			return i - 10101;
		if (i >= 10112 && i < 10121)
			return i - 10111;
		if (i >= 10122 && i < 10131)
			return i - 10121;

		return -1;
	}

	/**
	 * 获取位于指定字符串的指定索引位置的数值型字符的数字值。
	 * Params:
	 *		str = 要查询的字符串。
	 *		index = str 中的字符位置。
	 * Returns:
	 *		位于指定字符串的指定索引位置的数值型字符的数字值。
	 *		如果指定字符串的指定索引位置的数值型字符不是数字则返回 -1 。
	 * Throws:
	 *		AsserError，当 str 为 null 或者 index 超出了 str 中的有效索引范围。
	 * Comments:
	 *		ditto 。
	 */
	public static int getDigitValue(wstring str, int index)
	in
	{
		checkParameter(str, index);
	}
	body
	{
		return getDigitValue(str[index]);
	}

	/**
	 * 获取与指定字符关联的数值。
	 * Params:
	 * 		c = 要获取其数值的 Unicode 字符。
	 * Returns:
	 *		与指定的字符关联的数值。
	 *		如果指定的字符不是一个数值型字符则返回 -1.0 。
	 * Comments:
	 *		数值是一个仅应用于数值型字符的 Unicode 字符属性，数值型字符包括分数、下标、上标、罗马数字、货币分子、循环数和语言特有的数字。
	 */
	public static double getNumericValue(wchar c)
	{
		auto i = getDigitValue (c);
		if (i >= 0)
			return i;

		i = cast(int)c;

		switch (i) 
		{
			case 188:
				return 0.25;
			case 189:
				return 0.5;
			case 190:
				return 0.75;
			case 2548:
				return 1;
			case 2549:
				return 2;
			case 2550:
				return 3;
			case 2551:
				return 4;
			case 2553:
				return 16;
			case 3056:
				return 10;
			case 3057:
				return 100;
			case 3058:
				return 1000;
			case 4988:
				return 10000;
			case 5870:
				return 17;
			case 5871:
				return 18;
			case 5872:
				return 19;
			case 8531:
				return 1.0 / 3;
			case 8532:
				return 2.0 / 3;
			case 8537:
				return 1.0 / 6;
			case 8538:
				return 5.0 / 6;
			case 8539:
				return 1.0 / 8;
			case 8540:
				return 3.0 / 8;
			case 8541:
				return 5.0 / 8;
			case 8542:
				return 7.0 / 8;
			case 8543:
				return 1;
			case 8556:
				return 50;
			case 8557:
				return 100;
			case 8558:
				return 500;
			case 8559:
				return 1000;
			case 8572:
				return 50;
			case 8573:
				return 100;
			case 8574:
				return 500;
			case 8575:
				return 1000;
			case 8576:
				return 1000;
			case 8577:
				return 5000;
			case 8578:
				return 10000;
			case 9470: 			// WChar.isNumber(c) is False BTW.
			case 10111:
			case 10121:
			case 10131:
				return 10;
			case 12295:
				return 0;
			case 12344:
				return 10;
			case 12345:
				return 20;
			case 12346:
				return 30;
		}

		// They are not True by WChar.isNumber() but regarded as they were.
		if (9451 <= i && i < 9461)
			return i - 9440;
		if (12321 <= i && i < 12330)
			return i - 12320;
		if (12881 <= i && i < 12896)
			return i - 12860;
		if (12977 <= i && i < 12992)
			return i - 12941;

		if (!WChar.isNumber (c))
			return -1;

		if (i < 3891)
			return 0.5 + i - 3882;
		if (i < 4988)
			return (i - 4977) * 10;
		if (i < 8537)
			return 0.2 * (i - 8532);
		if (i < 8556)
			return i - 8543;
		if (i < 8572)
			return i - 8559;
		if (i < 9332)
			return i - 9311;
		if (i < 9352)
			return i - 9331;
		if (i < 9372)
			return i - 9351;
		if (i < 12694)
			return i - 12689;
		if (i < 12842)
			return i - 12831;
		if (i < 12938)
			return i - 12927;

		return -1;
	}

	/**
	 * 获取与位于指定字符串的指定索引位置的字符关联的数值。
	 * Params:
	 *		str = 要查询的字符串。
	 *		index = str 中的字符位置。
	 * Returns:
	 *		位于指定字符串的指定索引位置的字符关联的数值。 
	 *		如果位于指定字符串的指定索引位置的字符不是一个数值型字符则返回 -1 。
	 * Throws:
	 *		AsserError，当 str 为 null 或者 index 超出了 str 中的有效索引范围。
	 * Comments:
	 *		ditto 。
	 */
	public static double getNumericValue(wstring str, int index)
	in
	{
		checkParameter(str, index);
	}
	body
	{
		return getNumericValue(str[index]);
	}
	
	private static void checkParameter(wstring str, int index)
	{
		assert(str !is null, "The argument str can not be null.");
		assert(index >= 0 && index < str.length, "The value of index is less than zero, or greater than or equal to the length of str.");
	}
}